
// === uuArray ===
// depend: uuMeta
/*
Array.prototype.lastIndexOf(needle, fromIndex = length) - return index
Array.prototype.indexOf(needle, fromIndex = 0) - return index
Array.prototype.forEach(fn, thisArg = undef)
Array.prototype.filter(fn, thisArg = undef) - return Array
Array.prototype.every(fn, thisArg = undef) - return Array
Array.prototype.some(fn, thisArg = undef) - return Array
Array.prototype.map(fn, thisArg = undef) - return Array
Array.prototype.reduce(fn, initialValue = undef) - return Mix
Array.prototype.reduceRight(fn, initialValue = undef) - return Mix
uuMeta.toUniqueArray(ary, removeAlike) - return Array
 */
uuMeta.mix(Array.prototype, {
  // Array.prototype.lastIndexOf
  lastIndexOf: function(needle,       // @param Mix:
                        fromIndex) {  // @param Number(= this.length):
                                      // @return Number: index
    var iz = this.length, i = fromIndex;
    i = (i < 0) ? i + iz : iz - 1;

    for (; i > -1; --i) {
      if (i in this && this[i] === needle) {
        return i; // return found index
      }
    }
    return -1;
  },

  // Array.prototype.indexOf
  indexOf: function(needle,       // @param Mix:
                    fromIndex) {  // @param Number(= 0):
                                  // @return Number: index
    var iz = this.length, i = fromIndex || 0;
    i = (i < 0) ? i + iz : i;

    for (; i < iz; ++i) {
      if (i in this && this[i] === needle) {
        return i; // found index
      }
    }
    return -1;
  },

  // Array.prototype.forEach
  forEach: function(fn,         // @param Function: evaluator
                    thisArg) {  // @param ThisObject(= undefined):
    var i = 0, iz = this.length;

    for (; i < iz; ++i) {
      if (i in this) {
        fn.call(thisArg, this[i], i, this);
      }
    }
  },

  // Array.prototype.filter
  filter: function(fn,        // @param Function: evaluator
                   thisArg) { // @param ThisObject(= undefined):
                              // @return Array: [element, ... ]
    var rv = [], ri = -1, v, i = 0, iz = this.length;

    for (; i < iz; ++i) {
      if (i in this) {
        v = this[i];
        fn.call(thisArg, v, i, this) && (rv[++ri] = v);
      }
    }
    return rv;
  },

  // Array.prototype.every
  every: function(fn,        // @param Function: evaluator
                  thisArg) { // @param ThisObject(= undefined):
                             // @return Boolean:
    var i = 0, iz = this.length;

    for (; i < iz; ++i) {
      if (i in this) {
        if (!fn.call(thisArg, this[i], i, this)) {
          return false;
        }
      }
    }
    return true;
  },

  // Array.prototype.some
  some: function(fn,        // @param Function: evaluator
                 thisArg) { // @param ThisObject(= undefined):
                            // @return Boolean:
    var i = 0, iz = this.length;

    for (; i < iz; ++i) {
      if (i in this) {
        if (fn.call(thisArg, this[i], i, this)) {
          return true;
        }
      }
    }
    return false;
  },

  // Array.prototype.map
  map: function(fn,         // @param Function: evaluator
                thisArg) {  // @param ThisObject(= undefined):
                            // @return Array: [element, ... ]
    var rv = Array(this.length), i = 0, iz = this.length;

    for (; i < iz; ++i) {
      if (i in this) {
        rv[i] = fn.call(thisArg, this[i], i, this);
      }
    }
    return rv;
  },

  // Array.prototype.reduce
  reduce: function(fn,              // @param Function: evaluator
                   initialValue) {  // @param Mix(= undefined):
                                    // @return Mix:
    var rv, i = 0, iz = this.length, found = 0;

    if (initialValue !== void 0) {
      rv = initialValue;
      ++found;
    }
    for (; i < iz; ++i) {
      if (i in this) {
        if (found) {
          rv = fn(rv, this[i], i, this);
        } else {
          rv = this[i];
          ++found;
        }
      }
    }
    if (!found) { throw ""; }
    return rv;
  },

  // Array.prototype.reduceRight
  reduceRight: function(fn,             // @param Function: evaluator
                        initialValue) { // @param Mix(= undefined):
                                        // @return Mix:
    var rv, i = 0, found = 0;

    if (initialValue !== void 0) {
      rv = initialValue;
      ++found;
    }
    for (i = this.length - 1; i >= 0; --i) {
      if (i in this) {
        if (found) {
          rv = fn(rv, this[i], i, this);
        } else {
          rv = this[i];
          ++found;
        }
      }
    }
    if (!found) { throw ""; }
    return rv;
  }
}, 0, 0);

// uuMeta.toUniqueArray - compaction and remove alike value
uuMeta.toUniqueArray = function(ary,           // @param Array: source
                                removeAlike) { // @param Boolean(= true):
                                               // @return Array:
  var rv = [], ri = -1, v, i = 0, iz = ary.length,
      alike = (removeAlike === void 0) ? true : removeAlike;

  for (; i < iz; ++i) {
    if (i in ary) {
      v = ary[i];
      if (v !== null && v !== void 0) {
        (!alike || rv.indexOf(v) < 0) && (rv[++ri] = v);
      }
    }
  }
  return rv;
};
